package org.goldenport.g3.events.http

import java.io.{PrintWriter, StringWriter}
import javax.servlet.http.HttpServletResponse._
import org.apache.http.HttpEntity
import com.asamioffice.goldenport.util.OptionUtil.lift
import com.asamioffice.goldenport.text.UJson
import org.goldenport.g3._
import org.goldenport.g3.events._
import org.goldenport.g3.messages.{Record, RecordFieldException}

/**
 * @since   Sep. 21, 2010
 * @version Jan. 17, 2011
 * @version Dec   3, 2011
 * @author  ASAMI, Tomoharu
 */
// XXX important in error architecture. move to org.goldenport.g3 ?
abstract class HttpStatusEvent(uri: String, val exception: Option[Exception] = None,
                               val message: String = "", val errors: Option[Record] = None
                             ) extends G3Event(uri) with HttpEvent {
  val htmlType = "text/html;charset=utf-8"
  val atomType = "application/atom+xml;charset=utf-8"
  val jsonType = "application/json;charset=utf-8"
  protected val status_Code: Int

  protected def content_Text: String = {
    uri + "\n" +
    message + "\n" +
    exception.map( e => {
      e.getMessage + "\n" +
      stack_trace_text(e)
    }).mkString
  }

  protected final def stack_trace_text(e: Throwable) = {
    val sw = new StringWriter
    val out = new PrintWriter(sw)
    e.printStackTrace(out)
    sw.toString
  }

  protected def html_Text: String = {
    content_Text
  }

  protected def atom_Text: String = {
    content_Text
  }

  protected def is_success: Boolean = {
    errors.isEmpty
  }

  protected final def error_field(repository: String, cmd: G3Command): Option[(String, Map[String, String])] = {
    errors.map(r => "errors" -> Map[String, String](r.fields.toList.collect {
      case (k, e: RecordFieldException) => k.name -> e.toMessage(repository, cmd)
    }: _*))
  }

  protected def json_Text(ctx: String /* XXX */, cmd: G3Command): String = {
    val result = List(Some("success" -> is_success),
                      Some("message" -> message),
                      Some("statusCode" -> status_Code),
                      error_field(ctx, cmd))
// 'content' has a negative effect for Ext-JS
//                      Some("content" -> content_Text))
    UJson.tuples2Json(result.flatten)
  }

  def toHtml: G3HttpResponse = {
    new StringHttpResponse(html_Text, htmlType, status_Code)
  }

  def toAtom: G3HttpResponse = {
    new StringHttpResponse(atom_Text, atomType, status_Code)
  }

  def toJson(ctx: G3AgentContext, cmd: G3Command): G3HttpResponse = {
    new StringHttpResponse(json_Text(null, cmd), jsonType, status_Code)
  }

  def toJson(ctx: G3Context, cmd: G3Command): G3HttpResponse = {
    new StringHttpResponse(json_Text(null, cmd), jsonType, status_Code)
  }
}

class Http200(uri: String, exception: Option[Exception] = None,
              message: String = "OK" , errors: Option[Record] = None
            ) extends HttpStatusEvent(uri, exception, message, errors) {
  val status_Code = 200
}

object Http200 {
  def apply(uri: String, e: Exception = null, message: String = "OK", errors: Record = null) = {
    new Http200(uri, lift(e), message, lift(errors))
  }
}

class Http201(uri: String, exception: Option[Exception] = None,
              message: String = "Created" , errors: Option[Record] = None
            ) extends HttpStatusEvent(uri, exception, message, errors) {
  val status_Code = 201
}

object Http201 {
  def apply(uri: String, e: Exception = null, message: String = "Created", errors: Record = null) = {
    new Http201(uri, lift(e), message, lift(errors))
  }
}

class Http202(uri: String, exception: Option[Exception] = None,
              message: String = "Accepted" , errors: Option[Record] = None
            ) extends HttpStatusEvent(uri, exception, message, errors) {
  val status_Code = 202
}

object Http202 {
  def apply(uri: String, e: Exception = null, message: String = "Accepted", errors: Record = null) = {
    new Http202(uri, lift(e), message, lift(errors))
  }
}

class Http400(uri: String, exception: Option[Exception] = None,
              message: String = "Bad Request" , errors: Option[Record] = None
            ) extends HttpStatusEvent(uri, exception, message, errors) {
  val status_Code = 400
  override protected def is_success = false

/*
  override protected def json_Text(repository: String /* XXX */, cmd: G3Command): String = {
    val result = List(Some("success" -> false),
                      Some("message" -> message),
                      error_field(repository, cmd: G3Command))
    UJson.tuples2Json(result.flatten)
  }
*/
}

object Http400 {
  def apply(uri: String, e: Exception = null, message: String = "Bad Request", errors: Record = null) = {
    new Http400(uri, lift(e), message, lift(errors))
  }
}

class Http401(uri: String, exception: Option[Exception] = None,
              message: String = "Unauthorized"
            ) extends HttpStatusEvent(uri, exception, message) {
  val status_Code = 401
  override protected def is_success = false
}

object Http401 {
  def apply(uri: String, e: Exception = null, message: String = "Unauthorized") = {
    new Http401(uri, lift(e), message)
  }
}

class Http402(uri: String, exception: Option[Exception] = None,
              message: String = "Payment Required"
            ) extends HttpStatusEvent(uri, exception, message) {
  val status_Code = 402
  override protected def is_success = false
}

object Http402 {
  def apply(uri: String, e: Exception = null, message: String = "Payment Required") = {
    new Http402(uri, lift(e), message)
  }
}

class Http403(uri: String, exception: Option[Exception] = None,
              message: String = "Forbidden"
            ) extends HttpStatusEvent(uri, exception, message) {
  val status_Code = 403
  override protected def is_success = false
}

object Http403 {
  def apply(uri: String, e: Exception = null, message: String = "Forbidden") = {
    new Http403(uri, lift(e), message)
  }
}

class Http404(uri: String, exception: Option[Exception] = None,
              message: String = "Not Found"
            ) extends HttpStatusEvent(uri, exception, message) {
  val status_Code = 404
  override protected def is_success = false
}

object Http404 {
  def apply(uri: String, e: Exception = null, message: String = "Not Found") = {
    new Http404(uri, lift(e), message)
  }
}

class Http500(uri: String,
              exception: Option[Exception],
              message: String = "Internal Server Error"
            ) extends HttpStatusEvent(uri, exception, message) {
  val status_Code = 500
  override protected def is_success = false
}

object Http500 {
  def apply(uri: String, e: Exception = null, message: String = "Internal Server Error") = {
    new Http500(uri, Option(e), message)
  }
}

class Http501(uri: String,
              exception: Option[Exception],
              message: String = "Not Implemented"
            ) extends HttpStatusEvent(uri, exception, message) {
  val status_Code = 501
  override protected def is_success = false
}

object Http501 {
  def apply(uri: String, e: Exception = null, message: String = "Not Implemented") = {
    new Http501(uri, lift(e), message)
  }
}
